/***************************************************************************
 *	@file 		fetion_database.h
 *	@Author 	baoyu0125@gmail.com
 *	@create		2011-7
 *	@version 	1.0.0
 *	@brief		definition of class SQLiteStatement and SQLiteWrapper
 *				class SQLiteWrapper is wrapper of libsqlite3 functions
 *				class SQLiteStatement is about SQL statement of sqlite3
 *	@modify		none
 ***************************************************************************/

#ifndef FETION_DATABASE_H
#define FETION_DATABASE_H

#include <string>
#include <vector>
#include <sqlite3.h>
#include <iostream>

class SQLiteStatement
{
private:
	friend class SQLiteWrapper;
	// SQLiteStatement's ctor only to be called by SQLiteWrapper
	SQLiteStatement(std::string const& statement, sqlite3* db);//////////////

public:
	SQLiteStatement() : stmt_(NULL) { }	//////////////
	~SQLiteStatement();

	enum dataType {
		INT = SQLITE_INTEGER,
		FLT = SQLITE_FLOAT  ,
		TXT = SQLITE_TEXT   ,
		BLB = SQLITE_BLOB   ,
		NUL = SQLITE_NULL   ,
	};

	dataType DataType(int pos_zero_indexed);
	int ValueInt(int pos_zero_indexed);
	std::string ValueString(int pos_zero_indexed);

	//SQLiteStatement(const SQLiteStatement&);
	//SQLiteStatement& operator=(SQLiteStatement const&);

	bool Bind	(int pos_zero_indexed, std::string const& value);
	bool Bind(int pos_zero_indexed, double value);
	bool Bind	(int pos_zero_indexed, int value);
	bool BindNull	(int pos_zero_indexed);
	bool Execute();
	bool NextRow();
	/*   Call Reset if not depending on the NextRow cleaning up.
	For example for select count(*) statements*/
	bool Reset();
	bool RestartSelect();

private:
	sqlite3_stmt* stmt_;	// byte code of SQL statement, created by sqlite3_prepare() function
};

class SQLiteWrapper
{
public:
    SQLiteWrapper() : db_(NULL) { }

	~SQLiteWrapper()
	{
		if(NULL != db_) {
			sqlite3_close(db_);
		}
	}

	bool Open(std::string const& db_file);

	class ResultRecord
	{
	public:
		typedef std::vector<std::string>::iterator rr_iter;
		std::vector<std::string> fields_;
	};

	class ResultTable
	{
	public:
		friend class SQLiteWrapper;
		typedef std::vector<ResultRecord>::iterator rt_iter;
			
		ResultTable() : ptr_cur_record_(0) {}
		ResultRecord* next()
		{
			if (ptr_cur_record_ < records_.size()) {
				return &(records_[ptr_cur_record_++]);
			}
			return NULL;
		}

		std::vector<ResultRecord> records_;
	private:
		void reset()
		{
			records_.clear();
			ptr_cur_record_=0;
		}
	private:
	    unsigned int ptr_cur_record_;
	};

	bool SelectStmt(std::string const& stmt, ResultTable& res);
	bool DirectStatement(std::string const& stmt);
	SQLiteStatement* Statement(std::string const& stmt);

	std::string LastError();

	// Transaction related
	bool Begin();
	bool Commit();
	bool Rollback();
	bool End();

private:
	static int SelectCallback(void *p_data, int num_fields, char **p_fields, char **p_col_names);
	sqlite3* db_;
};

#endif
